• Jump To … +
    zoo_frontend/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js zoo_frontend/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.js zoo_frontend/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.min.js zoo_frontend/node_modules/hoist-non-react-statics/src/index.js zoo_frontend/pages/_app.jsx zoo_frontend/pages/_document.jsx zoo_frontend/pages/admin/delivery-containers/index.js zoo_frontend/pages/admin/department/index.js zoo_frontend/pages/admin/group-diets/index.js zoo_frontend/pages/admin/species/index.js zoo_frontend/pages/admin/user/index.js zoo_frontend/pages/diet/edit.js zoo_frontend/pages/diet/index.js zoo_frontend/pages/diet/new.js zoo_frontend/pages/food/dataSrc.js zoo_frontend/pages/food/edit.js zoo_frontend/pages/food/index.js zoo_frontend/pages/food/new.js zoo_frontend/pages/food/nicknames.js zoo_frontend/pages/food/nutrDef.js zoo_frontend/pages/food/units.js zoo_frontend/pages/home/index.js zoo_frontend/pages/index.jsx zoo_frontend/pages/kitchen/index.js zoo_frontend/pages/kitchen/prep/index.js zoo_frontend/pages/login/index.js zoo_frontend/pages/nutritionist/index.js zoo_frontend/pages/print/bin-label.js zoo_frontend/pages/print/index.js zoo_frontend/pages/print/labels.js zoo_frontend/pages/print/prep-sheet.js zoo_frontend/pages/profile/index.js zoo_frontend/pages/reports/cost-by-gl-code.js zoo_frontend/pages/reports/dept-cards.js zoo_frontend/pages/reports/dept-keeper-cards.js zoo_frontend/pages/reports/feeding-cost.js zoo_frontend/pages/reports/index.js zoo_frontend/pages/reports/prep-cards-table.js zoo_frontend/src/api/Animals.js zoo_frontend/src/api/Api.js zoo_frontend/src/api/BudgetIds.js zoo_frontend/src/api/CaseNotes.js zoo_frontend/src/api/DataSrc.js zoo_frontend/src/api/DeliveryContainers.js zoo_frontend/src/api/Departments.js zoo_frontend/src/api/DietChanges.js zoo_frontend/src/api/DietHistory.js zoo_frontend/src/api/DietPlans.js zoo_frontend/src/api/Diets.js zoo_frontend/src/api/Food.js zoo_frontend/src/api/FoodCategories.js zoo_frontend/src/api/FoodPrepTables.js zoo_frontend/src/api/FoodWeights.js zoo_frontend/src/api/LifeStages.js zoo_frontend/src/api/Locations.js zoo_frontend/src/api/NutData.js zoo_frontend/src/api/NutrDef.js zoo_frontend/src/api/PrepNotes.js zoo_frontend/src/api/RoleMappings.js zoo_frontend/src/api/Roles.js zoo_frontend/src/api/Species.js zoo_frontend/src/api/Subenclosures.js zoo_frontend/src/api/Units.js zoo_frontend/src/api/Users.js zoo_frontend/src/api/index.js zoo_frontend/src/components/ConfirmationDialog.jsx zoo_frontend/src/components/ErrorPage.jsx zoo_frontend/src/components/FormCheckbox.jsx zoo_frontend/src/components/Header.jsx zoo_frontend/src/components/KitchenView.jsx zoo_frontend/src/components/Notifications.jsx zoo_frontend/src/components/PrintPrepSheets/PrepSheetPrintOut.jsx zoo_frontend/src/components/PrintPrepSheets/PrintPrepSheets.jsx zoo_frontend/src/components/PrintPrepSheets/index.js zoo_frontend/src/components/ReactSingleSelect.jsx zoo_frontend/src/components/SidebarDrawer.jsx zoo_frontend/src/components/VirtualTable.jsx zoo_frontend/src/components/index.js zoo_frontend/src/getPageContext.js zoo_frontend/src/pages/PageAccess.js zoo_frontend/src/pages/admin/deliveryContainers/deliveryContainers.jsx zoo_frontend/src/pages/admin/deliveryContainers/deliveryContainers.styles.js zoo_frontend/src/pages/admin/deliveryContainers/index.js zoo_frontend/src/pages/admin/department/department.jsx zoo_frontend/src/pages/admin/department/department.styles.js zoo_frontend/src/pages/admin/department/index.js zoo_frontend/src/pages/admin/groupDiets/groupDiets.jsx zoo_frontend/src/pages/admin/groupDiets/groupDiets.styles.js zoo_frontend/src/pages/admin/groupDiets/index.js zoo_frontend/src/pages/admin/species/index.js zoo_frontend/src/pages/admin/species/species.jsx zoo_frontend/src/pages/admin/species/species.styles.js zoo_frontend/src/pages/admin/user/index.js zoo_frontend/src/pages/admin/user/user.jsx zoo_frontend/src/pages/admin/user/user.styles.js zoo_frontend/src/pages/diet/CaseNotesForm.jsx zoo_frontend/src/pages/diet/CurrentDiet.jsx zoo_frontend/src/pages/diet/DietChangeCard.jsx zoo_frontend/src/pages/diet/DietHistory.jsx zoo_frontend/src/pages/diet/DietPlanChangeDialog.jsx zoo_frontend/src/pages/diet/DietSelectDialog.jsx zoo_frontend/src/pages/diet/diet.jsx zoo_frontend/src/pages/diet/diet.styles.js zoo_frontend/src/pages/diet/dietForm.jsx zoo_frontend/src/pages/diet/dietHistoryList.jsx zoo_frontend/src/pages/diet/edit/edit.jsx zoo_frontend/src/pages/diet/edit/edit.styles.js zoo_frontend/src/pages/diet/edit/index.js zoo_frontend/src/pages/diet/index.js zoo_frontend/src/pages/diet/new/index.js zoo_frontend/src/pages/diet/new/new.jsx zoo_frontend/src/pages/diet/new/new.styles.js zoo_frontend/src/pages/diet/prepNotesForm.jsx zoo_frontend/src/pages/food/dataSrc/dataSrc.jsx zoo_frontend/src/pages/food/dataSrc/dataSrc.styles.js zoo_frontend/src/pages/food/dataSrc/index.js zoo_frontend/src/pages/food/edit/FoodWeightTable.jsx zoo_frontend/src/pages/food/edit/edit.jsx zoo_frontend/src/pages/food/edit/edit.styles.js zoo_frontend/src/pages/food/edit/index.js zoo_frontend/src/pages/food/food.jsx zoo_frontend/src/pages/food/food.styles.js zoo_frontend/src/pages/food/foodForm.jsx zoo_frontend/src/pages/food/index.js zoo_frontend/src/pages/food/new/index.js zoo_frontend/src/pages/food/new/new.jsx zoo_frontend/src/pages/food/new/new.styles.js zoo_frontend/src/pages/food/nicknames/index.js zoo_frontend/src/pages/food/nicknames/nicknames.jsx zoo_frontend/src/pages/food/nicknames/nicknames.styles.js zoo_frontend/src/pages/food/nutrDef/index.js zoo_frontend/src/pages/food/nutrDef/nutrDef.jsx zoo_frontend/src/pages/food/nutrDef/nutrDef.styles.js zoo_frontend/src/pages/food/units/index.js zoo_frontend/src/pages/food/units/units.jsx zoo_frontend/src/pages/food/units/units.styles.js zoo_frontend/src/pages/home/home.jsx zoo_frontend/src/pages/home/home.styles.js zoo_frontend/src/pages/home/index.js zoo_frontend/src/pages/kitchen/index.js zoo_frontend/src/pages/kitchen/kitchenHome.jsx zoo_frontend/src/pages/kitchen/kitchenHome.styles.js zoo_frontend/src/pages/kitchen/prep/index.js zoo_frontend/src/pages/kitchen/prep/kitchen.jsx zoo_frontend/src/pages/kitchen/prep/kitchen.styles.js zoo_frontend/src/pages/login/index.js zoo_frontend/src/pages/login/login.jsx zoo_frontend/src/pages/login/login.styles.js zoo_frontend/src/pages/nutritionist/admin.jsx zoo_frontend/src/pages/nutritionist/admin.styles.js zoo_frontend/src/pages/nutritionist/index.js zoo_frontend/src/pages/print/admin.jsx zoo_frontend/src/pages/print/admin.styles.js zoo_frontend/src/pages/print/bin-label/admin.jsx zoo_frontend/src/pages/print/bin-label/admin.styles.js zoo_frontend/src/pages/print/bin-label/index.js zoo_frontend/src/pages/print/index.js zoo_frontend/src/pages/print/labels/admin.jsx zoo_frontend/src/pages/print/labels/admin.styles.js zoo_frontend/src/pages/print/labels/index.js zoo_frontend/src/pages/print/prep-sheet/admin.jsx zoo_frontend/src/pages/print/prep-sheet/admin.styles.js zoo_frontend/src/pages/print/prep-sheet/index.js zoo_frontend/src/pages/profile/index.js zoo_frontend/src/pages/profile/profile.jsx zoo_frontend/src/pages/profile/profile.styles.js zoo_frontend/src/pages/reports/admin.jsx zoo_frontend/src/pages/reports/admin.styles.js zoo_frontend/src/pages/reports/cost-by-gl-code/admin.jsx zoo_frontend/src/pages/reports/cost-by-gl-code/admin.styles.js zoo_frontend/src/pages/reports/cost-by-gl-code/index.js zoo_frontend/src/pages/reports/dept-cards/admin.jsx zoo_frontend/src/pages/reports/dept-cards/admin.styles.js zoo_frontend/src/pages/reports/dept-cards/index.js zoo_frontend/src/pages/reports/dept-keeper-cards/admin.jsx zoo_frontend/src/pages/reports/dept-keeper-cards/admin.styles.js zoo_frontend/src/pages/reports/dept-keeper-cards/index.js zoo_frontend/src/pages/reports/feeding-cost/admin.jsx zoo_frontend/src/pages/reports/feeding-cost/admin.styles.js zoo_frontend/src/pages/reports/feeding-cost/index.js zoo_frontend/src/pages/reports/index.js zoo_frontend/src/pages/reports/prep-cards-table/admin.jsx zoo_frontend/src/pages/reports/prep-cards-table/admin.styles.js zoo_frontend/src/pages/reports/prep-cards-table/index.js zoo_frontend/src/static/LocalStorage.js zoo_frontend/src/static/Roles.js zoo_frontend/src/util/AuthProvider.jsx zoo_frontend/src/util/PageLayout.jsx zoo_frontend/src/util/TableColumnHelper.js zoo_frontend/src/util/WithPropsChecker.jsx zoo_frontend/src/util/camelToNorm.js zoo_frontend/src/util/withAuth.jsx
  • CurrentDiet.jsx

  • ¶
    import React, { Component } from 'react';
    import MaterialTable from 'material-table';
    
    import { MuiThemeProvider } from '@material-ui/core/styles';
    
    import PropTypes from 'prop-types';
    
    import { Button, CircularProgress, TextField } from '@material-ui/core';
    import { theme } from '../../getPageContext';
    
    /**
     * This function helps check if required fields have been met for new and edits on records
     */
    const dietPlanRequiredFieldCheck = (rowUpdated, showNotification) => {
      if (!rowUpdated.foodId) {
        showNotification('error', 'Food is a required field.');
        return false;
      }
    
      if (!rowUpdated.indAmount) {
        showNotification('error', 'Individual amount is a required field.');
        return false;
      }
      if (Number.isNaN(parseInt(rowUpdated.indAmount, 10))) {
        showNotification(
          'error',
          'Individual Amount is a number field. Please enter a number',
        );
        return false;
      }
    
      if (!rowUpdated.unitId) {
        showNotification('error', 'Unit is a required field.');
        return false;
      }
    
      if (!rowUpdated.sort) {
        showNotification('error', 'Sort is a required field.');
        return false;
      }
    
      if (Number.isNaN(parseInt(rowUpdated.sort, 10))) {
        showNotification('error', 'Sort is a number field. Please enter a number.');
        return false;
      }
    
      if (!rowUpdated.tote) {
        showNotification('error', 'Bag is a required field.');
        return false;
      }
    
      if (Number.isNaN(parseInt(rowUpdated.tote, 10))) {
        showNotification('error', 'Bag is a number field. Please enter a number.');
        return false;
      }
    
      if (!rowUpdated.freqRotation) {
        showNotification('error', 'Cycle is a required field.');
        return false;
      }
    
      if (Number.isNaN(parseInt(rowUpdated.freqRotation, 10))) {
        showNotification(
          'error',
          'Cycle is a number field. Please enter a number.',
        );
        return false;
      }
    
      if (!rowUpdated.freqWeeks) {
        showNotification('error', 'Week is a required field.');
        return false;
      }
    
      if (Number.isNaN(parseInt(rowUpdated.freqWeeks, 10))) {
        showNotification('error', 'Week is a number field. Please enter a number.');
        return false;
      }
    
      return true;
    };
    
    
    class CurrentDiet extends Component {
      static propTypes = {
        allFoods: PropTypes.arrayOf(PropTypes.object).isRequired,
        allUnits: PropTypes.arrayOf(PropTypes.object).isRequired,
        dietPlan: PropTypes.arrayOf(PropTypes.object),
        onSave: PropTypes.func.isRequired,
        showNotification: PropTypes.func.isRequired,
        numAnimals: PropTypes.number,
        currentDiet: PropTypes.object.isRequired,
        onDietPlanAdd: PropTypes.func.isRequired,
        onDietPlanUpdate: PropTypes.func.isRequired,
        onDietPlanDelete: PropTypes.func.isRequired,
        onNumAnimalsChange: PropTypes.func.isRequired,
        pendingChanges: PropTypes.bool.isRequired,
        editDisabled: PropTypes.bool,
      };
    
      static defaultProps = {
        numAnimals: 1,
        dietPlan: [],
        editDisabled: false,
      };
    
      constructor(props) {
        super(props);
    
        const foodLookup = {};
        props.allFoods.slice(0).reduce((acc, food) => {
          acc[food.foodId] = food.food;
          return acc;
        }, foodLookup);
    
        const unitLookup = {};
        props.allUnits.slice(0).reduce((acc, unit) => {
          acc[unit.unitId] = unit.unit;
          return acc;
        }, unitLookup);
    
        this.state = {
          deletedDietPlans: [],
          foodLookup,
          unitLookup,
          isLoading: false,
        };
    
        this.columns = [
          {
            title: 'Food',
            field: 'foodId',
            lookup: this.state.foodLookup,
            cellStyle: {
              width: '100px !important',
            },
          },
          {
            title: 'Ind',
            field: 'indAmount',
          },
          {
            title: 'Total',
            field: 'groupAmount',
            readonly: true,
            editable: 'never',
          },
          {
            title: 'Unit',
            field: 'unitId',
            lookup: this.state.unitLookup,
            cellStyle: {
              width: '30px',
            },
          },
          {
            title: 'SU',
            field: 'sun',
            type: 'boolean',
          },
          {
            title: 'M',
            field: 'mon',
            type: 'boolean',
          },
          {
            title: 'T',
            field: 'tue',
            type: 'boolean',
          },
          {
            title: 'W',
            field: 'wed',
            type: 'boolean',
          },
          {
            title: 'R',
            field: 'thr',
            type: 'boolean',
          },
          {
            title: 'F',
            field: 'fri',
            type: 'boolean',
          },
          {
            title: 'S',
            field: 'sat',
            type: 'boolean',
          },
          {
            title: 'Sort',
            field: 'sort',
            defaultSort: 'asc',
          },
          {
            title: 'Bag',
            field: 'tote',
          },
          {
            title: 'Cycle',
            field: 'freqRotation',
          },
          {
            title: 'Week',
            field: 'freqWeeks',
          },
        ];
      }
    
      render() {
        return (
          <div
            style={{
              position: 'relative',
              display: 'flex',
              flexDirection: 'column',
            }}
          >
            <MuiThemeProvider
              theme={{
                ...theme,
                overrides: {
                  MuiTableCell: {
                    root: {
                      textAlign: 'center',
                      padding: '0px 4px 0px 4px',
                    },
                    paddingCheckbox: {
                      padding: '0px 2px 0px 2px',
                    },
                  },
                  MuiSelect: {
                    select: {
                      maxWidth: '100px',
                    },
                  },
                  MuiIconButton: {
                    root: {
                      padding: '5px 5px 5px 5px',
                    },
                  },
                  MuiTableSortLabel: {
                    icon: {
                      display: 'none',
                    },
                  },
                  MuiIcon: {
                    root: {
                      width: '1em !important',
                    },
                  },
                },
              }}
            >
              <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                <TextField
                  variant="outlined"
                  type="number"
                  value={this.props.numAnimals}
                  onChange={e => {
                    let val = parseInt(e.target.value, 10);
                    if (val <= 0) {
                      val = 1;
                    }
    
                    this.props.onNumAnimalsChange(val);
                  }}
                  style={{ margin: '10px' }}
                  label="Number of Animals"
                  disabled={this.props.editDisabled}
                />
                <div style={{ display: 'flex' }}>
                  <Button
                    onClick={() => {
                      this.setState({ isLoading: true }, () => {
  • ¶

    isloading and pending changes get changed via ref. This is because changelog dialog can only be opened via state change which can’t be listend to via a promise chain when it is completed.

                        this.props.onSave(this.state.deletedDietPlans);
                      });
                    }}
                    variant="contained"
                    color="primary"
                    style={{
                      marginRight: '15px',
                      marginTop: '10px',
                      marginBottom: '10px',
                      width: '200px',
                    }}
                    disabled={!this.props.pendingChanges}
                  >
                    Submit Changes
                  </Button>
                </div>
              </div>
              {this.props.editDisabled ?
                <MaterialTable
                  title="Current Diet Plan"
                  columns={this.columns}
                  data={this.props.dietPlan}
                  options={{
                    pageSize: this.props.dietPlan.length + 10,
                    search: false,
                    emptyRowsWhenPaging: false,
                    addRowPosition: 'first',
    
                  }}
                />
                :
                <MaterialTable
                  title="Current Diet Plan"
                  columns={this.columns}
                  data={this.props.dietPlan}
                  options={{
                    pageSize: this.props.dietPlan.length + 10,
                    search: false,
                    emptyRowsWhenPaging: false,
                    addRowPosition: 'first',
    
                  }}
                  editable={{
                    onRowAdd: newData => new Promise((res, rej) => {
                      const valid = dietPlanRequiredFieldCheck(
                        newData,
                        this.props.showNotification,
                      );
    
                      const localData = { ...newData };
                      localData.groupAmount =
                        this.props.numAnimals * parseInt(localData.indAmount, 10);
                      localData.dietId = this.props.currentDiet.dietId;
                      if (!valid) {
                        rej();
                        return;
                      }
  • ¶

    update via props to prevent issues with updating state once diets have been created via ‘submit changes’ button

                      this.props.onDietPlanAdd(localData).then(() => {
                        res();
                      });
                    }),
    
    
                    onRowDelete: row => new Promise((res, rej) => {
                      this.props
                        .onDietPlanDelete(row)
                        .then(() => {
                          this.setState(
                            prevState => ({
                              deletedDietPlans: [...prevState.deletedDietPlans, row],
                            }),
                            () => {
                              res();
                            },
                          );
                        })
                        .catch(err => {
                          console.error(err);
                          rej();
                        });
                    }),
    
                    onRowUpdate: (rowUpdated, prevRow) => new Promise(async (res, rej) => {
                      const valid = dietPlanRequiredFieldCheck(
                        rowUpdated,
                        this.props.showNotification,
                      );
                      if (!valid) {
                        rej();
                        return;
                      }
    
                      const updatedCopy = { ...rowUpdated };
                      updatedCopy.groupAmount = this.props.numAnimals * parseInt(updatedCopy.indAmount, 10);
                      let fieldUpdated = false;
                      const updatedFields = Object.entries(updatedCopy)
                        .filter(column => prevRow[column[0]] !== column[1])
                        .map(entry => entry[0]);
                      if (updatedFields && updatedFields.length > 0) {
                        fieldUpdated = true;
                      }
                      if (fieldUpdated) {
                        const updatedFieldsToServer = {};
                        updatedFields.forEach(fieldToKeep => {
                          updatedFieldsToServer[fieldToKeep] =
                            updatedCopy[fieldToKeep];
                        });
                        await this.props.onDietPlanUpdate(updatedFieldsToServer, updatedCopy.id).catch((err) => {
                          console.error(err);
                          rej();
                        });
                        res();
                        return;
                      }
                      this.props.showNotification(
                        'info',
                        'No pending changes detected',
                      );
                      rej();
                    }),
                  }}
                />
              }
              {this.state.isLoading && (
                <div
                  style={{
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    height: '100%',
                    width: '100%',
                    zIndex: 999999,
                  }}
                >
                  <div
                    style={{
                      display: 'table',
                      width: '100%',
                      height: '100%',
                      backgroundColor: '#FFFFFFAA',
                    }}
                  >
                    <div
                      style={{
                        display: 'table-cell',
                        width: '100%',
                        height: '100%',
                        verticalAlign: 'middle',
                        textAlign: 'center',
                      }}
                    >
                      <CircularProgress />
                    </div>
                  </div>
                </div>
              )}
            </MuiThemeProvider>
          </div>
        );
      }
    }
    
    export default CurrentDiet;